{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Prompt Template\n",
    "\n",
    "- Author: [Hye-yoon Jeong](https://github.com/Hye-yoonJeong)\n",
    "- Peer Review : [hyeyeoon](https://github.com/hyeyeoon), [Wooseok Jeong](https://github.com/jeong-wooseok)\n",
    "- Proofread : [Q0211](https://github.com/Q0211)\n",
    "- This is a part of [LangChain Open Tutorial](https://github.com/LangChain-OpenTutorial/LangChain-OpenTutorial)\n",
    "\n",
    "[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/LangChain-OpenTutorial/LangChain-OpenTutorial/blob/main/02-Prompt/01-PromptTemplate.ipynb)",
    "[![Open in GitHub](https://img.shields.io/badge/Open%20in%20GitHub-181717?style=flat-square&logo=github&logoColor=white)](https://github.com/LangChain-OpenTutorial/LangChain-OpenTutorial/blob/main/02-Prompt/01-PromptTemplate.ipynb)",
    "\n",
    "## Overview\n",
    "This tutorial covers how to create and utilize prompt templates using ```LangChain```.\n",
    "\n",
    "Prompt templates are essential for generating dynamic and flexible prompts that cater to various use cases, such as conversation history, structured outputs, and specialized queries.\n",
    "\n",
    "In this tutorial, we will explore methods for creating ```PromptTemplate``` objects, applying partial variables, managing templates through YAML files, and leveraging advanced tools like ```ChatPromptTemplate``` and ```MessagePlaceholder``` for enhanced functionality.\n",
    "\n",
    "### Table of Contents\n",
    "- [Overview](#overview)\n",
    "- [Environment Setup](#environment-setup)\n",
    "- [Creating a PromptTemplate Object](#creating-a-prompttemplate-object)\n",
    "- [Using partial_variables](#using-partial_variables)\n",
    "- [Load Prompt Templates from YAML Files](#load-prompt-templates-from-yaml-files)\n",
    "- [ChatPromptTemplate](#chatprompttemplate)\n",
    "- [MessagePlaceholder](#messageplaceholder)\n",
    "\n",
    "### References\n",
    "- [LangChain Documentation : Prompts](https://python.langchain.com/api_reference/core/prompts.html#)\n",
    "----"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Environment Setup\n",
    "\n",
    "Set up the environment. You may refer to [Environment Setup](https://wikidocs.net/257836) for more details.\n",
    "\n",
    "**[Note]**\n",
    "- ```langchain-opentutorial``` is a package that provides a set of easy-to-use environment setup, useful functions and utilities for tutorials. \n",
    "- You can check out the [```langchain-opentutorial```](https://github.com/LangChain-OpenTutorial/langchain-opentutorial-pypi) for more details."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "[notice] A new release of pip is available: 24.1 -> 24.3.1\n",
      "[notice] To update, run: python.exe -m pip install --upgrade pip\n"
     ]
    }
   ],
   "source": [
    "%%capture --no-stderr\n",
    "%pip install langchain-opentutorial"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Install required packages\n",
    "from langchain_opentutorial import package\n",
    "\n",
    "package.install(\n",
    "    [\n",
    "        \"langsmith\",\n",
    "        \"langchain\",\n",
    "        \"langchain_core\",\n",
    "        \"langchain_community\",\n",
    "        \"langchain_openai\",\n",
    "    ],\n",
    "    verbose=False,\n",
    "    upgrade=False,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from dotenv import load_dotenv\n",
    "\n",
    "load_dotenv(override=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Environment variables have been set successfully.\n"
     ]
    }
   ],
   "source": [
    "# Set environment variables\n",
    "from langchain_opentutorial import set_env\n",
    "\n",
    "set_env(\n",
    "    {\n",
    "        # \"OPENAI_API_KEY\": \"\",\n",
    "        # \"LANGCHAIN_API_KEY\": \"\",\n",
    "        \"LANGCHAIN_TRACING_V2\": \"true\",\n",
    "        \"LANGCHAIN_ENDPOINT\": \"https://api.smith.langchain.com\",\n",
    "        \"LANGCHAIN_PROJECT\": \"Prompt-Template\",\n",
    "    }\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's setup ```ChatOpenAI``` with ```gpt-4o``` model."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "# Load the model\n",
    "llm = ChatOpenAI(model_name=\"gpt-4o\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Creating a ```PromptTemplate``` Object\n",
    "\n",
    "There are two ways to create a ```PromptTemplate``` object.\n",
    "- 1. Using the ```from_template()``` method\n",
    "- 2. Creating a ```PromptTemplate``` object and a prompt all at once"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Method 1. Using the ```from_template()``` method\n",
    "\n",
    "- Define template with variable as ```{variable}``` ."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "PromptTemplate(input_variables=['country'], input_types={}, partial_variables={}, template='What is the capital of {country}?')"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_core.prompts import PromptTemplate\n",
    "\n",
    "# Define template. In this case, {country} is a variable\n",
    "template = \"What is the capital of {country}?\"\n",
    "\n",
    "# Create a `PromptTemplate` object using the `from_template` method\n",
    "prompt = PromptTemplate.from_template(template)\n",
    "prompt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can complete the prompt by assigning a value to the variable ```country``` ."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'What is the capital of United States of America?'"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Create prompt. Assign value to the variable using `format` method\n",
    "prompt = prompt.format(country=\"United States of America\")\n",
    "prompt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Define template\n",
    "template = \"What is the capital of {country}?\"\n",
    "\n",
    "# Create a `PromptTemplate` object using the `from_template` method\n",
    "prompt = PromptTemplate.from_template(template)\n",
    "\n",
    "# Create chain\n",
    "chain = prompt | llm"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'The capital of the United States of America is Washington, D.C.'"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Replace the country variable with a value of your choice\n",
    "chain.invoke(\"United States of America\").content"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Method 2. Creating a ```PromptTemplate``` object and a prompt all at once\n",
    "\n",
    "Explicitly specify ```input_variables``` for additional validation.\n",
    "\n",
    "Otherwise, a mismatch between such variables and the variables within the template string can raise an exception in instantiation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "PromptTemplate(input_variables=['country'], input_types={}, partial_variables={}, template='What is the capital of {country}?')"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Define template\n",
    "template = \"What is the capital of {country}?\"\n",
    "\n",
    "# Create a prompt template with `PromptTemplate` object\n",
    "prompt = PromptTemplate(\n",
    "    template=template,\n",
    "    input_variables=[\"country\"],\n",
    ")\n",
    "prompt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'What is the capital of United States of America?'"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Create prompt\n",
    "prompt.format(country=\"United States of America\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "PromptTemplate(input_variables=['country1'], input_types={}, partial_variables={'country2': 'United States of America'}, template='What are the capitals of {country1} and {country2}, respectively?')"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Define template\n",
    "template = \"What are the capitals of {country1} and {country2}, respectively?\"\n",
    "\n",
    "# Create a prompt template with `PromptTemplate` object\n",
    "prompt = PromptTemplate(\n",
    "    template=template,\n",
    "    input_variables=[\"country1\"],\n",
    "    partial_variables={\n",
    "        \"country2\": \"United States of America\"  # Pass `partial_variables` in dictionary form\n",
    "    },\n",
    ")\n",
    "prompt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'What are the capitals of South Korea and United States of America, respectively?'"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "prompt.format(country1=\"South Korea\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "PromptTemplate(input_variables=['country1'], input_types={}, partial_variables={'country2': 'India'}, template='What are the capitals of {country1} and {country2}, respectively?')"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "prompt_partial = prompt.partial(country2=\"India\")\n",
    "prompt_partial"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'What are the capitals of South Korea and India, respectively?'"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "prompt_partial.format(country1=\"South Korea\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "chain = prompt_partial | llm"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'The capital of the United States of America is Washington, D.C., and the capital of India is New Delhi.'"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chain.invoke(\"United States of America\").content"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'The capital of the United States of America is Washington, D.C., and the capital of India is New Delhi.'"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chain.invoke({\"country1\": \"United States of America\", \"country2\": \"India\"}).content"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Using ```partial_variables```\n",
    "\n",
    "Using ```partial_variables``` , you can partially apply functions.  This is particularly useful when there are **common variables** to be shared.\n",
    "\n",
    "Common examples are **date or time**.\n",
    "\n",
    "Suppose you want to specify the current date in your prompt, hardcoding the date into the prompt or passing it along with other input variables may not be practical. In this case, using a function that returns the current date to modify the prompt partially is much more convenient."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'January 14'"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from datetime import datetime\n",
    "\n",
    "# Print the current date\n",
    "datetime.now().strftime(\"%B %d\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Define function to return the current date\n",
    "def get_today():\n",
    "    return datetime.now().strftime(\"%B %d\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "prompt = PromptTemplate(\n",
    "    template=\"Today's date is {today}. Please list {n} celebrities whose birthday is today. Please specify their date of birth.\",\n",
    "    input_variables=[\"n\"],\n",
    "    partial_variables={\n",
    "        \"today\": get_today  # Pass `partial_variables` in dictionary form\n",
    "    },\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\"Today's date is January 14. Please list 3 celebrities whose birthday is today. Please specify their date of birth.\""
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Create prompt\n",
    "prompt.format(n=3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Create chain\n",
    "chain = prompt | llm"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Here are three celebrities born on January 14:\n",
      "\n",
      "1. **Dave Grohl** - Born on January 14, 1969.\n",
      "2. **LL Cool J** - Born on January 14, 1968.\n",
      "3. **Jason Bateman** - Born on January 14, 1969.\n"
     ]
    }
   ],
   "source": [
    "# Invoke chain and check the result\n",
    "print(chain.invoke(3).content)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Here are three celebrities born on January 2:\n",
      "\n",
      "1. **Cuba Gooding Jr.** - Born on January 2, 1968.\n",
      "2. **Taye Diggs** - Born on January 2, 1971.\n",
      "3. **Kate Bosworth** - Born on January 2, 1983.\n"
     ]
    }
   ],
   "source": [
    "# Invoke chain and check the result\n",
    "print(chain.invoke({\"today\": \"Jan 02\", \"n\": 3}).content)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Load Prompt Templates from YAML Files\n",
    "\n",
    "You can manage prompt templates in seperate yaml files and load using ```load_prompt``` ."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "PromptTemplate(input_variables=['fruit'], input_types={}, partial_variables={}, template='What is the color of {fruit}?')"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_core.prompts import load_prompt\n",
    "\n",
    "prompt = load_prompt(\"prompts/fruit_color.yaml\", encoding=\"utf-8\")\n",
    "prompt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'What is the color of an apple?'"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "prompt.format(fruit=\"an apple\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Please provide information about the capital city of United States of America.\n",
      "Summarize the characteristics of the capital in the following format, within 300 words.\n",
      "----\n",
      "[Format]\n",
      "1. Area\n",
      "2. Population\n",
      "3. Historical Sites\n",
      "4. Regional Products\n",
      "\n",
      "#Answer:\n",
      "\n"
     ]
    }
   ],
   "source": [
    "prompt2 = load_prompt(\"prompts/capital.yaml\")\n",
    "print(prompt2.format(country=\"United States of America\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## ```ChatPromptTemplate```\n",
    "\n",
    "```ChatPromptTemplate``` can be used to include a conversation history as a prompt.\n",
    "\n",
    "Messages are structured as tuples in the format (```role``` , ```message``` ) and are created as a list.\n",
    "\n",
    "**role**\n",
    "- ```system``` : A system setup message, typically used for global settings-related prompts.\n",
    "- ```human``` : A user input message.\n",
    "- ```ai``` : An AI response message."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "ChatPromptTemplate(input_variables=['country'], input_types={}, partial_variables={}, messages=[HumanMessagePromptTemplate(prompt=PromptTemplate(input_variables=['country'], input_types={}, partial_variables={}, template='What is the capital of {country}?'), additional_kwargs={})])"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "\n",
    "chat_prompt = ChatPromptTemplate.from_template(\"What is the capital of {country}?\")\n",
    "chat_prompt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Human: What is the capital of United States of America?'"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chat_prompt.format(country=\"United States of America\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[SystemMessage(content='You are a friendly AI assistant. Your name is Teddy.', additional_kwargs={}, response_metadata={}),\n",
       " HumanMessage(content='Nice to meet you!', additional_kwargs={}, response_metadata={}),\n",
       " AIMessage(content='Hello! How can I assist you?', additional_kwargs={}, response_metadata={}),\n",
       " HumanMessage(content='What is your name?', additional_kwargs={}, response_metadata={})]"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "\n",
    "chat_template = ChatPromptTemplate.from_messages(\n",
    "    [\n",
    "        # role, message\n",
    "        (\"system\", \"You are a friendly AI assistant. Your name is {name}.\"),\n",
    "        (\"human\", \"Nice to meet you!\"),\n",
    "        (\"ai\", \"Hello! How can I assist you?\"),\n",
    "        (\"human\", \"{user_input}\"),\n",
    "    ]\n",
    ")\n",
    "\n",
    "# Create chat messages\n",
    "messages = chat_template.format_messages(name=\"Teddy\", user_input=\"What is your name?\")\n",
    "messages"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can directly invoke LLM using the messages created above."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'My name is Teddy. How can I help you today?'"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "llm.invoke(messages).content"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can also create a chain to execute."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [],
   "source": [
    "chain = chat_template | llm"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'My name is Teddy. How can I help you today?'"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chain.invoke({\"name\": \"Teddy\", \"user_input\": \"What is your name?\"}).content"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## ```MessagePlaceholder```\n",
    "\n",
    "```LangChain``` also provides a ```MessagePlaceholder``` , which provides complete control over rendering messages during formatting.\n",
    "\n",
    "This can be useful if you’re unsure which roles to use in a message prompt template or if you want to insert a list of messages during formatting."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "ChatPromptTemplate(input_variables=['conversation', 'word_count'], input_types={'conversation': list[typing.Annotated[typing.Union[typing.Annotated[langchain_core.messages.ai.AIMessage, Tag(tag='ai')], typing.Annotated[langchain_core.messages.human.HumanMessage, Tag(tag='human')], typing.Annotated[langchain_core.messages.chat.ChatMessage, Tag(tag='chat')], typing.Annotated[langchain_core.messages.system.SystemMessage, Tag(tag='system')], typing.Annotated[langchain_core.messages.function.FunctionMessage, Tag(tag='function')], typing.Annotated[langchain_core.messages.tool.ToolMessage, Tag(tag='tool')], typing.Annotated[langchain_core.messages.ai.AIMessageChunk, Tag(tag='AIMessageChunk')], typing.Annotated[langchain_core.messages.human.HumanMessageChunk, Tag(tag='HumanMessageChunk')], typing.Annotated[langchain_core.messages.chat.ChatMessageChunk, Tag(tag='ChatMessageChunk')], typing.Annotated[langchain_core.messages.system.SystemMessageChunk, Tag(tag='SystemMessageChunk')], typing.Annotated[langchain_core.messages.function.FunctionMessageChunk, Tag(tag='FunctionMessageChunk')], typing.Annotated[langchain_core.messages.tool.ToolMessageChunk, Tag(tag='ToolMessageChunk')]], FieldInfo(annotation=NoneType, required=True, discriminator=Discriminator(discriminator=<function _get_type at 0x0000020B148D7E20>, custom_error_type=None, custom_error_message=None, custom_error_context=None))]]}, partial_variables={}, messages=[SystemMessagePromptTemplate(prompt=PromptTemplate(input_variables=[], input_types={}, partial_variables={}, template='You are a summarization specialist AI assistant. Your mission is to summarize conversations using key points.'), additional_kwargs={}), MessagesPlaceholder(variable_name='conversation'), HumanMessagePromptTemplate(prompt=PromptTemplate(input_variables=['word_count'], input_types={}, partial_variables={}, template='Summarize the conversation so far in {word_count} words.'), additional_kwargs={})])"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_core.output_parsers import StrOutputParser\n",
    "from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder\n",
    "\n",
    "chat_prompt = ChatPromptTemplate.from_messages(\n",
    "    [\n",
    "        (\n",
    "            \"system\",\n",
    "            \"You are a summarization specialist AI assistant. Your mission is to summarize conversations using key points.\",\n",
    "        ),\n",
    "        MessagesPlaceholder(variable_name=\"conversation\"),\n",
    "        (\"human\", \"Summarize the conversation so far in {word_count} words.\"),\n",
    "    ]\n",
    ")\n",
    "chat_prompt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can use ```MessagesPlaceholder``` to add the conversation message list."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "System: You are a summarization specialist AI assistant. Your mission is to summarize conversations using key points.\n",
      "Human: Hello! I’m Teddy. Nice to meet you.\n",
      "AI: Nice to meet you! I look forward to working with you.\n",
      "Human: Summarize the conversation so far in 5 words.\n"
     ]
    }
   ],
   "source": [
    "formatted_chat_prompt = chat_prompt.format(\n",
    "    word_count=5,\n",
    "    conversation=[\n",
    "        (\"human\", \"Hello! I’m Teddy. Nice to meet you.\"),\n",
    "        (\"ai\", \"Nice to meet you! I look forward to working with you.\"),\n",
    "    ],\n",
    ")\n",
    "\n",
    "print(formatted_chat_prompt)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Create chain\n",
    "chain = chat_prompt | llm | StrOutputParser()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Teddy introduces himself, exchanges greetings.'"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Invoke chain and check the result\n",
    "chain.invoke(\n",
    "    {\n",
    "        \"word_count\": 5,\n",
    "        \"conversation\": [\n",
    "            (\n",
    "                \"human\",\n",
    "                \"Hello! I'm Teddy. Nice to meet you.\",\n",
    "            ),\n",
    "            (\"ai\", \"Nice to meet you! I look forward to working with you.\"),\n",
    "        ],\n",
    "    }\n",
    ")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "langchain-kr-ARohChI8-py3.11",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}